﻿using System;
using System.Collections.Generic;
using System.Linq;
using Matrix.Common;
using System.ComponentModel;

namespace Matrix.ViewModel
{
   public class MatrixInstance : IMatrix
   {
      private int maxColumnSize = 8;
      private int maxRowSize = 8;
      #region IMatrix Members
      public MatrixInstance()
      {
         Initialize();
      }

      private void Initialize()
      {
         for (int i = 0; i < maxColumnSize; i++)
         {
            for (int j = 0; j < maxRowSize; j++)
            {
               MatrixElements element = new MatrixElements(i, j);
               this.elements.Add(element);
            }
         }

         ToIdentity();
         Resize();
      }

      private void ToZeroMatrix()
      {
         foreach (var element in this.Elements)
         {
            element.ElementValue = 0;
         }
      }

      private void ToIdentity()
      {
         ToZeroMatrix();
         for (int i = 0; i < maxColumnSize; i++)
         {
            var qElement = from m in Elements
                           where m.RowPosition == i && m.ColumnPosition == i
                           select m;
            foreach (var element in qElement)
            {
               element.ElementValue = 1;
            }
         }
      }

      IMatrixElement getElement(int row, int col)
      {
         return (from m in Elements
                where m.ColumnPosition == col && m.RowPosition == row
                select m).FirstOrDefault();
      }

      public Matrix.Data.Matrix MatrixElement
      {
         get
         {
            Matrix.Data.Matrix matrix = new Data.Matrix(this.RowSize, this.ColumnSize);
            foreach (var element in this.ValidElements)
            {
               matrix[element.RowPosition, element.ColumnPosition] = element.ElementValue;
            }
            return matrix;
         }
         set
         {
            for (int i = 0; i < value.rows; i++)
            {
               for (int j = 0; j < value.cols; j++)
               {
                  var element = getElement(i, j);
                  element.ElementValue = value[i, j];
               }
            }
         }

      }

      public IEnumerable<IMatrixElement> ValidElements
      {
         get
         {
            return from m in Elements
                   where m.IsValid == true
                   select m;
         }
      }

      public void Resize()
      {
         var qValid = from m in elements
                     where m.ColumnPosition < this.columnSize || m.RowPosition < rowSize
                     select m;
         foreach (var qElement in qValid)
         {
            qElement.IsValid = true;
         }
         var qList = from m in elements
                     where m.ColumnPosition >= this.columnSize || m.RowPosition >= rowSize
                     select m;

         foreach (var qElement in qList)
         {
            qElement.IsValid = false;
         }
      }

      bool isValid;
      public bool IsValid
      {
         get
         {
            return isValid;
         }
         set
         {
            isValid = value;
            OnPropertyChanged("IsValid");
         }
      }

      private int columnSize = 3;
      public int ColumnSize
      {
         get
         {
            return columnSize;
         }
         set
         {
            if (value > 0 && value < maxColumnSize)
            {
               columnSize = value;
               Resize();
               OnMatrixSizeChanged();
            }
            else
            {
               columnSize = maxColumnSize;
               Resize();
               OnMatrixSizeChanged();
            }
            OnPropertyChanged("ColumnSize");
         }
      }

      private int rowSize = 3;
      public int RowSize
      {
         get
         {
            return rowSize;
         }
         set
         {
            if (value > 0 && value < maxRowSize)
            {
               rowSize = value;
               Resize();
               OnMatrixSizeChanged();

            }
            else
            {
               rowSize = maxRowSize;
               Resize();
               OnMatrixSizeChanged();
            }
            OnPropertyChanged("RowSize");
         }
      }

      private bool isEditable = true;
      public bool IsEditable
      {
         get
         {
            return isEditable;
         }
         set
         {
            isEditable = value;
            foreach (var element in this.elements)
            {
               element.IsEditable = value;
            }
            OnPropertyChanged("IsEditable");
         }
      }


      #endregion

      #region INotifyPropertyChanged Members

      public event PropertyChangedEventHandler PropertyChanged;

      private void OnPropertyChanged(string propertyName)
      {
         if (PropertyChanged != null)
         {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
         }
      }

      #endregion

      #region IMatrix Members
      private List<MatrixElements> elements = new List<MatrixElements>();
      public IEnumerable<IMatrixElement> Elements
      {
         get
         {
            return elements;
         }
      }

      #endregion

      #region IMatrix Members

      public event EventHandler MatrixSizeChanged;

      private void OnMatrixSizeChanged()
      {
         if (MatrixSizeChanged != null)
         {
            MatrixSizeChanged(this, null);
         }
      }

      #endregion
   }
}
